/**
 * <p>Project: </p>
 * <p>File: math.c</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2016</p>
 * @author 王树根
 * @email: wangshugen@ict.ac.cn
 * @date 2016年6月6日
 */

#include <math.h>

/**
 * 求绝对值
 * @n 待求的数
 */
int32_t abs(int32_t n) {
	return n > 0 ? n : -n;
}

/**
 * 计算幂的函数，产生的结果不能够太大
 * @base 底数
 * @n 指数, 正整数
 */
int32_t pow(int32_t base, int32_t n) {
	register volatile int i = 0;
	int32_t product = 1;
	while (++i <= n) {
		product *= base;
	}

	return product;
}

/**
 * 计算幂的函数，底数为2，产生的结果不能够太大
 * @n 指数, 正整数
 */
int32_t pow2(int32_t n) {
	register volatile int i = 0;
	int32_t product = 1;
	while (++i <= n) {
		product *= 2;
	}

	return product;
}

/**
 * 对n求整对数，其中@n必须为@base的整数次幂，否则报错
 * @base 底数
 * @n 真数
 */
size_t log(int32_t base, int32_t n) {
	assert(n > 0 && base > 0);

	size_t cnt = 0;
	while (pow(base, cnt) < n) {
		++cnt;
	}

	// 必须刚好为整次幂
	assert(pow(base, cnt) == n);

	return cnt;
}

/**
 * 对@n求以2为底的对数
 */
size_t log2(int32_t n) {
	return log(2, n);
}

/**
 * 对@n以@base为底的对数向上取整
 * @base 底数
 * @n 真数
 */
size_t log_round_up(int32_t base, int32_t n) {
	assert(n > 0 && base > 0);

	size_t cnt = 0;
	while (pow(base, cnt) < n) {
		++cnt;
	}

	return cnt;
}

/**
 * 对@n以@base为底的对数向下取整
 * @base 底数
 * @n 真数
 */
size_t log_round_down(int32_t base, int32_t n) {
	assert(n > 0 && base > 0);

	size_t cnt = 0;
	while (pow(base, cnt) < n) {
		++cnt;
	}

	return (pow(base, cnt) == n ? cnt : --cnt);
}

/**
 * 对@n以2为底的对数向上取整
 * @n 真数
 */
size_t log2_round_up(int32_t n) {
	return log_round_up(2, n);
}

/**
 * 对@n以2为底的对数向下取整
 * @n 真数
 */
size_t log2_round_down(int32_t n) {
	return log_round_down(2, n);
}

#ifdef _USE_DEBUG
#include <stdio.h>
static void unit_test(void) {
	// 数学函数测试
//	cprintf("log(2, 16)\n", log(2, 16));
//	cprintf("log(2, 15)\n", log(2, 15));
//	cprintf("pow(2,0): %d\n", pow(2, 0));
//	cprintf("pow(2,1): %d\n", pow(2, 1));
//	cprintf("pow2(6): %d\n", pow2(6));
//	cprintf("pow(8,3): %d\n", pow(8, 3));

	cprintf("log_round_down(2, 15): %d\n", log_round_down(2, 15));
	cprintf("log_round_down(2, 16): %d\n", log_round_down(2, 16));
	cprintf("log_round_down(2, 17): %d\n", log_round_down(2, 17));
	cprintf("log2_round_down(15): %d\n", log2_round_down(15));
	cprintf("log2_round_down(16): %d\n", log2_round_down(16));
	cprintf("log2_round_down(17): %d\n", log2_round_down(17));

	cprintf("log_round_up(2, 15): %d\n", log_round_up(2, 15));
	cprintf("log_round_up(2, 16): %d\n", log_round_up(2, 16));
	cprintf("log_round_up(2, 17): %d\n", log_round_up(2, 17));
	cprintf("log2_round_up(15): %d\n", log2_round_up(15));
	cprintf("log2_round_up(16): %d\n", log2_round_up(16));
	cprintf("log2_round_up(17): %d\n", log2_round_up(17));
}
#endif
